package libx

import (
	"math/rand"
	"regexp"
	"strings"
	"time"
)

// UpperCamelCaseToSnakeCase converts a string from UpperCamelCase to snake_case.
func UpperCamelCaseToSnakeCase(s string) string {
	var matchAllCap = regexp.MustCompile("([A-Z])([A-Z][a-z])|([a-z0-9])([A-Z])")

	snake := matchAllCap.ReplaceAllString(s, "${1}${3}_${2}${4}")

	return strings.ToLower(snake)
}

const (
	letterBytes   = "abcdefghijklmnopqrstuvwxyz0123456789"
	letterIdxBits = 6                    // 6 bits to represent a letter index
	letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
	letterIdxMax  = 63 / letterIdxBits   // # of letter indices fitting in 63 bits
)

// RandString32 generates a random 32-character string with lowercase letters and numbers.
func RandString32() string {
	var src = rand.NewSource(time.Now().UnixNano())
	b := make([]byte, 32)
	// A src.Int63() generates 63 random bits, enough for letterIdxMax characters!
	for i, cache, remain := 32-1, src.Int63(), letterIdxMax; i >= 0; {
		if remain == 0 {
			cache, remain = src.Int63(), letterIdxMax
		}
		idx := int(cache & letterIdxMask)
		if idx < len(letterBytes) {
			b[i] = letterBytes[idx]
			i--
		}
		cache >>= letterIdxBits
		remain--
	}

	return string(b)
}
